package com.vlyman.rsa;

import com.vlyman.utils.ByteUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类描述：
 *  针对 /rsa/Barrett.js
 *      /rsa/BigInt.js
 *      /rsa/RSA.js
 *  使用的RSA工具类，针对与前端通讯加密的工具方法
 * @author chenjs
 * @date 2019/1/12 14:04
 **/
@Slf4j
public class RsaUtilForJs {

    /**
     * 方法描述：
     *   私钥解密RSA.js用公钥加密的数据（应用于服务器端）
     *  @author chenjs
     *  @param data 待解密数据
     *  @return 解密后数据
     *  @date 2019/1/12 14:06
     */
    public static String decyrpt(String data) {
        String msg = null;
        try {
            log.info("原始待解密数据：" + data);
            msg = "";
            String[] results = data.split(" ");
            for (int i=0 ;i<results.length ;i++) {
                String result = results[i];
                //byte[] en_result = new BigInteger(result, 16).toByteArray(); // 此方法有bug采用hexStringToBytes
                byte[] enResult = ByteUtil.hexStringToBytes(result);
                byte[] deResult = RsaUtil.privateDecrypt(enResult,
                        (RSAPrivateKey) RsaKeyCreator.getKeyPair().getPrivate());
                StringBuffer sb = new StringBuffer();
                sb.append(new String(deResult));
                msg += sb.reverse().toString();
            }
            msg = URLDecoder.decode(msg, "UTF-8");
            log.info("解密后还原数据：" + msg);
        } catch (Exception e) {
            log.error("RSAForJs解密数据失败！", e);
        }
        return msg;
    }
    /**
     * 方法描述：
     *   公钥加密数据（针对RSA.js）
     *  @author chenjs
     *  @param data 待加密数据
     *  @return 加密后数据
     *  @date 2019/1/12 14:25
     */
    public static String encrypt(String data) throws Exception {
        try {
            log.info("原始待加密数据：" + data);
            data = URLEncoder.encode(data, "UTF-8");
            /**
             * 将input拆成长度为62的String加密,在JS中各个解密在拼接后使用decodeURIComponent
             * 62的取值详见RSA.js中this.chunkSize信息
             */
            int splitLen = 62;
            int splitCnt = data.length() / splitLen ;
            List<String> splitArr = new ArrayList<String>();
            //循环处理62整数倍
            for (int i = 0 ; i < splitCnt ; i++){
                String tmp = data.substring(splitLen * i , splitLen * (i + 1) );
                tmp = new StringBuffer().append(tmp).reverse().toString();
                tmp = ByteUtil.toHexString(tmp);
                byte[] t = RsaUtil.publicEncrypt(ByteUtil.hexStringToBytes(tmp),
                        (RSAPublicKey) RsaKeyCreator.getKeyPair().getPublic());
                String hexStr = ByteUtil.byte2hex(t);
                splitArr.add(hexStr);
            }
            //单独处理剩余字符串处理
            int splitRem = data.length() % splitLen;
            if(splitRem != 0){
                String tmp = data.substring(data.length() - splitRem);
                tmp = new StringBuffer().append(tmp).reverse().toString();
                tmp = ByteUtil.toHexString(tmp);
                byte[] t = RsaUtil.publicEncrypt(ByteUtil.hexStringToBytes(tmp),
                        (RSAPublicKey) RsaKeyCreator.getKeyPair().getPublic());
                String hexStr = ByteUtil.byte2hex(t);
                splitArr.add(hexStr);
            }
            return splitArr.stream().collect(Collectors.joining());
        } catch (Exception e) {
            log.error("RSAForJs加密数据失败！", e);
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        String msg = "50bb483c421eade8484dda72559f49ce7918047e3e190c99ff194d2153f90fca396f2eefd75caee78433f341aeaaa2f4ebfb6b7c94c22910f3f60a38ec02a04cf7e4578bb2564346ecce8966fc4bcf5e455d51b6b431a818bcff1a51807676ffdcb238239bd1053e260eff68140e26b0ea3f5027f42486e14e4b9f7021542b26";
        String demsg = RsaUtilForJs.decyrpt(msg);
        System.out.println(demsg);
        String data = "vlyman用户@chenjs";
        String enData = RsaUtilForJs.encrypt(data);
        System.out.println(enData);
    }
}
